<!doctype html>
<html class="no-js" lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>
    
  Effective Objective-c 2.0 学习笔记 - kaelinda
  
  </title>
  
  
  <link href="atom.xml" rel="alternate" title="kaelinda" type="application/atom+xml">
    <link rel="stylesheet" href="asset/css/foundation.min.css" />
    <link rel="stylesheet" href="asset/css/docs.css" />
    <script src="asset/js/vendor/modernizr.js"></script>
    <script src="asset/js/vendor/jquery.js"></script>
  <script src="asset/highlightjs/highlight.pack.js"></script>
  <link href="asset/highlightjs/styles/github.css" media="screen, projection" rel="stylesheet" type="text/css">
  <script>hljs.initHighlightingOnLoad();</script>
<script type="text/javascript">
  function before_search(){
    var searchVal = 'site:kaelinda.top ' + document.getElementById('search_input').value;
    document.getElementById('search_q').value = searchVal;
    return true;
  }
</script>
  </head>
  <body class="antialiased hide-extras">
    
    <div class="marketing off-canvas-wrap" data-offcanvas>
      <div class="inner-wrap">


<nav class="top-bar docs-bar hide-for-small" data-topbar>


  <section class="top-bar-section">
  <div class="row">
      <div style="position: relative;width:100%;"><div style="position: absolute; width:100%;">
        <ul id="main-menu" class="left">
        
        <li id=""><a target="_self" href="index.html">最近更新</a></li>
        
        <li id=""><a target="_self" href="archives.html">归档目录</a></li>
        
        <li id="ios.css"><a target="_self" href="ios.html">iOS</a></li>
        
        <li id="swift.css"><a target="_self" href="swift.html">Swift</a></li>
        
        <li id="reactnative.css"><a target="_self" href="reactnative.html">RN</a></li>
        
        <li id="js.css"><a target="_self" href="js.html">JS</a></li>
        
        <li id="shell.css"><a target="_self" href="shell.html">shell</a></li>
        
        <li id="coding.css"><a target="_self" href="coding.html">编程</a></li>
        
        <li id="live.css"><a target="_self" href="live.html">随笔</a></li>
        
        <li id="app.css"><a target="_blank" href="app.html">APP推荐</a></li>
        
        </ul>

        <ul class="right" id="search-wrap">
          <li>
<form target="_blank" onsubmit="return before_search();" action="http://google.com/search" method="get">
    <input type="hidden" id="search_q" name="q" value="" />
    <input tabindex="1" type="search" id="search_input"  placeholder="Search"/>
</form>
</li>
          </ul>
      </div></div>
  </div>
  </section>

</nav>

        <nav class="tab-bar show-for-small">
  <a href="javascript:void(0)" class="left-off-canvas-toggle menu-icon">
    <span> &nbsp; kaelinda</span>
  </a>
</nav>

<aside class="left-off-canvas-menu">
      <ul class="off-canvas-list">
        
        <li><a target="_self" href="index.html">最近更新</a></li>
        
        <li><a target="_self" href="archives.html">归档目录</a></li>
        
        <li><a target="_self" href="ios.html">iOS</a></li>
        
        <li><a target="_self" href="swift.html">Swift</a></li>
        
        <li><a target="_self" href="reactnative.html">RN</a></li>
        
        <li><a target="_self" href="js.html">JS</a></li>
        
        <li><a target="_self" href="shell.html">shell</a></li>
        
        <li><a target="_self" href="coding.html">编程</a></li>
        
        <li><a target="_self" href="live.html">随笔</a></li>
        
        <li><a target="_blank" href="app.html">APP推荐</a></li>
        

    <li><label>Categories</label></li>

        
            <li><a href="reactnative.html">React-Native</a></li>
        
            <li><a href="ios.html">iOS</a></li>
        
            <li><a href="app.html">MacAPP</a></li>
        
            <li><a href="swift.html">Swift</a></li>
        
            <li><a href="js.html">JavaScript</a></li>
        
            <li><a href="vue.html">Vue</a></li>
        
            <li><a href="shell.html">shell</a></li>
        
            <li><a href="%E7%BD%91%E7%BB%9C.html">网络</a></li>
         

      </ul>
    </aside>

<a class="exit-off-canvas" href="#"></a>


        <section id="main-content" role="main" class="scroll-container">
        
       

 <script type="text/javascript">
  $(function(){
    $('#menu_item_index').addClass('is_active');
  });
</script>
<div class="row">
  <div class="large-8 medium-8 columns">
      <div class="markdown-body article-wrap">
       <div class="article">
          
          <h1>Effective Objective-c 2.0 学习笔记</h1>
     
        <div class="read-more clearfix">
          <span class="date">2017/12/12</span>

          <span>posted in&nbsp;</span> 
          
              <span class="posted-in"><a href='ios.html'>iOS</a></span>
           
         
          <span class="comments">
            

            
          </span>

        </div>
      </div><!-- article -->

      <div class="article-content">
      <p>编写高质量iOS与OS X代码的52个有效方法</p>

<h1 id="toc_0">第一章 熟悉Objective-C</h1>

<h2 id="toc_1">第1条 了解Objective-C语言的起源</h2>

<ol>
<li>笔记：</li>
<li>OC是动态语言，使用<code>消息结构</code>(messaging structure),而非<code>函数调用</code>(function calling)。OC由消息语言的鼻祖smalltalk演化而来。</li>
<li>区别：消息结构的语言，其运行时执行的代码由运行环境决定；函数调用的语言，则由编译器决定。</li>
<li>OC中对象所占内存总是分配在<code>堆空间</code>(heap space)而不会在<code>栈空间</code>(stack)上</li>
<li><p>OC中不带*的变量，有可能会使用<code>栈空间</code>，比如CGRect 结构体</p>
<pre><code class="language-text">struct CGRect{
    CGPoint point;<br/>
    CGSize size;<br/>
};
</code></pre>
<p>因为创建对象需要额外开销（分配&amp;释放堆内存），从效率上，结构体性能更好。</p></li>
<li><p>要点</p></li>
<li><p>Objective-c为C语言天减了面向对象特性，是其超集。Objective-C是使用动态绑定的消息结构，也就是说，在运行时才会检查对象类型。接收这一消息后，究竟该执行何种代码实现，有运行期环境决定而非编译器。</p></li>
<li><p>理解C语言的核心概念有助于写好Objective-C程序，尤其是掌握内存模型与指针。</p></li>
</ol>

<span id="more"></span><!-- more -->

<h2 id="toc_2">第2条 在类的头文件中尽量少引用其他头文件。</h2>

<ol>
<li>笔记：</li>
<li>头文件导入时，如非使用者必须知道，尽量将头文件的导入时机延后（头文件的导入反倒.m文件中），这样会大大减少编译时间，减少头文件之间相互依赖的复杂度。</li>
<li><p>前向声明---<code>@class ClassName</code>这种头文件的声明方式(或者引入方式)叫做<code>前向声明</code>（或者向前声明）--- (forward declaring);前向声明方式引入的头文件，不会在编译期间进行编译，只是向声明我这里有这么各类，你知道有就行了，不需要你编译。这种方式还能解决头文件相互包含的问题。</p></li>
<li><p>要点：</p></li>
<li><p>除非有必要条件，否则不要引入头文件。一般来说，应在某各类的头文件中使用前向声明来提及别的类，并在实现文件中引入哪些类的头文件。这样做可以尽量降低类之间的<code>耦合</code>（coupling）</p></li>
<li><p>有时无法使用前向声明，比如要声明某个类遵循一项协议。这情况下，尽量把“该类遵循某协议”的这条生命移至&quot;class-continuation分类&quot;中。如果不行的话，就把协议单独放在一个头文件中，然后将其引入。</p></li>
</ol>

<h2 id="toc_3">第3条 多用字面量语法，少用与之等价的方法</h2>

<pre><code class="language-text"> //字面量语法
 NSString *str1 = @&quot;Kael&quot;;
 
 //传统方式
 NSString *str2 = [[NSString alloc] initWithFormat: @&quot;Kael&quot;];
</code></pre>

<ol>
<li>笔记：</li>
<li>字面量语法（literal syntax）能极大的缩短代码长度，使其更易读。</li>
<li><p>字面数值 传统方式：<code>NSNumber *someNumber = [NSNumber numberWithInt:1]</code></p>
<ol>
<li><code>NSNumber *intNumber = @1</code></li>
<li><code>NSNumber *floatNumbser = @0.125f</code></li>
<li><code>NSNumber *doubleNum = @3.14159</code></li>
<li><code>NSNumber *boolNum = @YES</code></li>
<li><code>NSNumber *charNum = @&#39;abc&#39;</code></li>
</ol></li>
</ol>

<ul>
<li>字面量数组 传统方式：<code>NSArray *animals = [NSArray arrayWithObjects:@&quot;cat&quot;,@&quot;dog&quot;,@&quot;mouse&quot;,nil];</code>
<ul>
<li><code>NSArray *animals = @[@&quot;cat&quot;,@&quot;dog&quot;,@&quot;mouse&quot;];</code></li>
<li><code>NSString *dog = animals[1];</code></li>
<li><code>replaceObjectAtIndex:index</code> -&gt; <code>mutableArray[1] = @&quot;dog&quot;;</code></li>
</ul></li>
<li><p>字面量字典 传统方式：<code>NSDictionary *personData = [NSDictionary dictionaryWithObjectsAndkeys:@&quot;kael&quot;,@&quot;name&quot;,@&quot;age&quot;,@&quot;18&quot;,nil];</code></p>
<ul>
<li><code>NSDictionary *personData = @{@&quot;name&quot;:@&quot;kael&quot;,@&quot;age&quot;:@&quot;18&quot;}</code></li>
<li><code>NSString *name = personData[@&quot;name&quot;];</code></li>
<li><code>setObject:obj forKey:key</code> -&gt; <code>mutableDic[name] = @&quot;kaelinda&quot;;</code></li>
</ul></li>
</ul>

<ol>
<li>要点：
<ol>
<li>字面量语法创建 字符串、数值、数组、字典 比常规方法更加简明扼要。</li>
<li>应该通过取下标方式来取 字典、数组 中的值。</li>
<li>用字面量语法创建数组或者字典时，若值中有nil,则会抛出异常。因此，务必确保值中不含nil。</li>
</ol></li>
</ol>

<h2 id="toc_4">第4条 多用类型常量，少用#define 预处理命令</h2>

<ol>
<li><p>笔记：</p>
<ol>
<li>宏定义等用于处理命令 是在编译器 编译期间 将定义的 字符替换，所以这样的缺点是 不能很好的从宏定义上读出常量的类型信息。</li>
<li><code>static const NSTimeInterval kAnimationinDuration = 0.3;</code></li>
<li><code>extern NSString *const EOCString;</code>比如 通知等需要有一个外部可见的变量作为 <strong>通知名</strong></li>
</ol></li>
<li><p>要点：</p>
<ol>
<li>不要用预处理指令定义常量。这样定义出来的常量不含类型信息，编译器编译期间，已经把这些值写死了，如果有人对常量改动，编译器也不会产生警告信息；</li>
<li>在实现文件中(.m文件)使用<code>static const</code>来定义只在编译单元可见(只在.m文件中可见，不暴露给外部使用)的常量。因此常量不在全局符号表中，命名上不需要在名称上加前缀。</li>
<li>在头文件中用<code>extern</code>来声明全局常量，并在相关实现文件中定义其值。</li>
</ol></li>
</ol>

<h2 id="toc_5">建议：处理隐藏的返回类型，优先选择实例类型而非id类型</h2>

<ol>
<li>笔记：
<ol>
<li><code>instancetype</code>仅仅用作Objective-C方法的返回类型</li>
<li><code>instancetype</code>有类型检测，更安全
*</li>
</ol></li>
</ol>

<h2 id="toc_6">建议：尽量使用模块方式与多类建立复合关系</h2>

<ul>
<li><code>#import</code> 和 <code>#include</code> 其根本就是简单的复制、粘贴，将.h文件中的内容一字不落的复制到当前文件中，<code>#import</code>可避免头文件的重复引用。</li>
<li>以预编译头文件的方式，虽然可以缩短编译时间，但维护棘手，不利于广泛应用。</li>
<li>模块功能，其应用不仅仅变现与编译的速度加快，同事在链接框架等方面也非常好用。</li>
<li>启动模块功能后，编译器会隐式的把所有的<code>#import</code>转换成<code>@import</code></li>
</ul>

<h2 id="toc_7">高度警惕空指针和野指针的袭击</h2>

<ol>
<li><p>笔记：</p>
<ol>
<li>nil、Nil、NULL的区别：<br/>
nil：指向oc中对象的空指针，针对对象。<br/>
Nil：指向oc中类的空指针，针对类。<br/>
NULL：指向其他类型的空指针，如一个c类型的内存指针，基本数据类型为空，基本类型。<br/>
NSNull：在集合对象中，表示空值的对象。</li>
</ol></li>
<li><p>要点：</p>
<ol>
<li>空指针（NULL）指的是没有存储任何内存地址的指针；野指针，是指向“垃圾内存”（不可用内存）的指针。</li>
<li>利用野指针发消息是很危险的，会报错。也就是说，一个对象被回收了，就不要再去操作它，不要尝试给它发消息。</li>
<li>利用空指针发消息是没有任何问题的，也就是说代码是没有错误的。</li>
</ol></li>
</ol>

<h2 id="toc_8">清楚常量字符串和一般字符串的区别</h2>

<pre><code class="language-text"> NSString *string1 = @&quot;hello&quot;;
 NSString *string2 = @&quot;hello&quot;
 if (strng1 == string2){
     NSLog(@&quot;They are same address&quot;);
 };
 
 NSString *string3 = [NSString alloc];
 nsstring *string4 = [string3 initWithString:string1];
 if (string3!=string4){
     NSLog(@&quot;string3 is not same to string4&quot;);
 }
 
 if (string1 == string4){
     NSLog(@&quot;string1 is same to string4&quot;);
 }
 
</code></pre>

<ul>
<li>由于编译器的优化，相同内容的常量字符串的地址是完全相同的。</li>
<li>如果用常量字符串来初始化一个字符串，那么这两个字符串也将是相同的常量。</li>
<li>对常量字符串永远不要release,因为多次release都还能访问。</li>
</ul>

<h2 id="toc_9">第5条 用枚举表示状态、选项、状态码</h2>

<ol>
<li>笔记：</li>
<li>想要将多个枚举能同时生效（例如，屏幕的方向），那需要枚举值设置为 2 的n次幂；</li>
<li><p>还可以通过按位操作</p></li>
</ol>

<ul>
<li><p>NS_ENUM与NS_OPTIONS区别：</p>
<ul>
<li>NS_ENUM枚举项的值为NSInteger，NS_OPTIONS枚举项的值为NSUInteger；</li>
<li>NS_ENUM定义通用枚举，NS_OPTIONS定义位移枚举</li>
<li>NS_OPTIONS的枚举项的值需要像这样表示1 &lt;&lt; 0，1 &lt;&lt; 1，2的几次方这样，而NS_ENUM可以直接给像1，2，3这样</li>
</ul></li>
</ul>

<ol>
<li>要点：</li>
<li>在处理枚举类型的switch语句时，不要使用default分支，这样加入新枚举时编译器会提醒开发者：switch语句并未处理所有枚举。</li>
</ol>

<hr/>

<h1 id="toc_10">第二章</h1>

<hr/>

<h2 id="toc_11">第6条 理解属性这一概念</h2>

<ol>
<li><p>笔记：</p>
<ul>
<li>属性(property) = 成员变量 + getter + setter</li>
<li>创建属性后，编译器会自动生成setter、getter属性</li>
</ul>
<p>属性特质：</p>
<ol>
<li>原子性：nonatomic 线程不安全；atomic 原子性，通过线程锁定等保证其原子性；</li>
<li>读/写权限：readwrite———可读可写（setter、getter）;readonly———只读。</li>
<li>内存管理语义：assign（弱引用）、weak（弱引用）、strong(强引用)、copy(强引用)、unsafe_unretained(针对于对象的 类似于assign)</li>
<li>方法名：
<ul>
<li><code>getter=&lt;name&gt;</code> --&gt; 指定“获取方法”的方法名  @property （nonatomic,getter=isOn）BOOL on;</li>
<li><code>seeter=&lt;name&gt;</code> --&gt; 指定设置方法的方法名 @property （nonatomic,getter=isOn,seeter=setBaseModelName）BOOL on;</li>
</ul></li>
</ol></li>
</ol>

<h2 id="toc_12">第7条 在对象内部尽量直接访问实例变量</h2>

<ul>
<li>直接访问实例变量，不会走<code>方法派送</code>(method dispatch);直接访问实例变量速度上要快得多。</li>
<li>直接访问实例变量，不会调用“设置方法”（setter）,ARC下copy修饰的属性，就不会copy该属性，只会保留新值并释放旧值。</li>
<li>直接访问实例变量，不会触发“键值观察（Key-ValueObserving，KVO）”</li>
<li>通过属性访问，可以通过setter、getter增加断点监控键值变化。</li>
</ul>

<p>折中：设置变量时走setter方法；获取变量值时直接访问实例变量；</p>

<p>注意：</p>

<ul>
<li>初始化方法(或者 dealloc)中设置属性值的时候，应该直接访问实例变量，因为子类可能会<code>覆写</code>该方法;</li>
<li>惰性初始化来配置数据，这时候需要通过属性来读取数据。</li>
</ul>

<h2 id="toc_13">第8条 理解“对象等同性”这一概念</h2>

<ol>
<li>笔记：<br/>
对象等同性比较：</li>
<li><code>==</code>比较的是指针本身</li>
<li><code>isEqual:</code>方法比较的是指针指向的内存地址</li>
</ol>

<p>NSobject协议中有两个判断等同性的关键方法：</p>

<pre><code class="language-text"> -(BOOL)isEqual:(id)object;
 -(NSUInteger)hash;
</code></pre>

<ol>
<li>要点：</li>
<li>相同的对象必须具有相同的哈希码；</li>
<li>拥有相同哈希码的对象不一定相同；</li>
</ol>

<h2 id="toc_14">第9条 以“类族模式”隐藏实现细节</h2>

<p>1.笔记：</p>

<ul>
<li>基类  + 分工的子类</li>
<li>子类都应当继承自类族中的抽象基类。</li>
<li>子类应该定义自己的数据存储方式。</li>
<li><p>子类应当覆写超类文档中指明需要覆写的方法。</p>
<p>2.要点:</p></li>
<li><p>类族模式可以把实现细节隐藏在一套简单的公共接口后面。</p></li>
<li><p>系统框架中经常使用类族。</p></li>
<li><p>从类族的公共抽象基类中集成子类是要当心，若文档有变化，则应当先阅读。</p></li>
</ul>

<h2 id="toc_15">第10条：在既有类中使用关联对象存放自定义数据</h2>

<h2 id="toc_16">第12条：理解 objc_msgSend 的作用</h2>

<h2 id="toc_17">第13条：</h2>

<h2 id="toc_18">第14条：</h2>

<h2 id="toc_19">第15条：</h2>

<h2 id="toc_20">第16条：</h2>

<h2 id="toc_21">第17条：</h2>

<h2 id="toc_22">第18条：</h2>

<h2 id="toc_23">第19条：</h2>

<h2 id="toc_24">第20条：</h2>

<h2 id="toc_25">第21条：</h2>

<h2 id="toc_26">第22条：</h2>

<h2 id="toc_27">第23条：</h2>


    

      </div>

      <div class="row">
        <div class="large-6 columns">
        <p class="text-left" style="padding:15px 0px;">
      
          <a href="15130871866705.html" 
          title="Previous Post: 当虹云直播SDK植入引导">&laquo; 当虹云直播SDK植入引导</a>
      
        </p>
        </div>
        <div class="large-6 columns">
      <p class="text-right" style="padding:15px 0px;">
      
          <a  href="15129168744096.html" 
          title="Next Post: 关于iOS沙盒文件的那些事儿">关于iOS沙盒文件的那些事儿 &raquo;</a>
      
      </p>
        </div>
      </div>
      <div class="comments-wrap">
        <div class="share-comments">
          

          

          
        </div>
      </div>
    </div><!-- article-wrap -->
  </div><!-- large 8 -->




 <div class="large-4 medium-4 columns">
  <div class="hide-for-small">
    <div id="sidebar" class="sidebar">
          <div id="site-info" class="site-info">
            
                <div class="site-a-logo"><img src="https://ws1.sinaimg.cn/large/006tNc79ly1fmpk9088gsj30sg0sgn33.jpg" /></div>
            
                <h1>kaelinda</h1>
                <div class="site-des">倘若我心中的山水，你眼中能看到，我便一步一莲花祈祷</div>
                <div class="social">








<a target="_blank" class="twitter" target="_blank" href="https://twitter.com/KaelLVLinda" title="Twitter">Twitter</a>
<a target="_blank" class="github" target="_blank" href="https://github.com/Kaelzzs" title="GitHub">GitHub</a>
<a target="_blank" class="email" href="mailto:zhouzuosong_kael@163.com" title="Email">Email</a>
  <a target="_blank" class="rss" href="atom.xml" title="RSS">RSS</a>
                
              	 </div>
          	</div>

             

              <div id="site-categories" class="side-item ">
                <div class="side-header">
                  <h2>Categories</h2>
                </div>
                <div class="side-content">

      	<p class="cat-list">
        
            <a href="reactnative.html"><strong>React-Native</strong></a>
        
            <a href="ios.html"><strong>iOS</strong></a>
        
            <a href="app.html"><strong>MacAPP</strong></a>
        
            <a href="swift.html"><strong>Swift</strong></a>
        
            <a href="js.html"><strong>JavaScript</strong></a>
        
            <a href="vue.html"><strong>Vue</strong></a>
        
            <a href="shell.html"><strong>shell</strong></a>
        
            <a href="%E7%BD%91%E7%BB%9C.html"><strong>网络</strong></a>
         
        </p>


                </div>
              </div>

              <div id="site-categories" class="side-item">
                <div class="side-header">
                  <h2>Recent Posts</h2>
                </div>
                <div class="side-content">
                <ul class="posts-list">
	      
		      
			      <li class="post">
			        <a href="15523077857608.html">OC中枚举写法  以及 字符串枚举探索</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15522686353535.html">iOS 动画全解 (1)</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15501356584731.html">UITableView顶部空白的几种解决办法</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15488351784332.html">Objective-C中的字符串类型枚举 探索</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15409691048860.html">【Swift笔记】引用计数</a>
			      </li>
		     
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		   
		  		</ul>
                </div>
              </div>
        </div><!-- sidebar -->
      </div><!-- hide for small -->
</div><!-- large 4 -->

</div><!-- row -->

 <div class="page-bottom clearfix">
  <div class="row">
   <p class="copyright">Copyright &copy; 2015
Powered by <a target="_blank" href="http://www.mweb.im">MWeb</a>,&nbsp; 
Theme used <a target="_blank" href="http://github.com">GitHub CSS</a>.</p>
  </div>
</div>

        </section>
      </div>
    </div>

  
    

    <script src="asset/js/foundation.min.js"></script>
    <script>
      $(document).foundation();
      function fixSidebarHeight(){
        var w1 = $('.markdown-body').height();
          var w2 = $('#sidebar').height();
          if (w1 > w2) { $('#sidebar').height(w1); };
      }
      $(function(){
        fixSidebarHeight();
      })
      $(window).load(function(){
          fixSidebarHeight();
      });
     
    </script>

    
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script type="text/x-mathjax-config">MathJax.Hub.Config({TeX: { equationNumbers: { autoNumber: "AMS" } }});</script>


  </body>
</html>
